github.com/NebulousLabs/Sia@v1.3.7/doc/Running and Writing Tests for Sia.md (about)

     1  # Running and Writing Tests for Sia
     2  Improving test coverage is a great way to start contributing to Sia.  
     3  
     4  This guide focuses on how to write tests.  To learn about making pull requests
     5  to submit the code you've written, see
     6  [doc/Guide to Contributing to Sia.md][guide].  You should also read
     7  [doc/Developers.md][developers] to learn about Sia code conventions and quality
     8  standards.
     9  
    10  
    11  #### Table of Contents
    12  * [Running tests for Sia](#existing)
    13    * [Updating code before testing](#update)
    14    * [Testing the entire build](#entire)
    15    * [Testing a particular package](#particular)
    16  * [Writing new tests for Sia](#write)
    17    * [A few guidelines](#naming)
    18    * [Basic test format](#basic)
    19    * [Table-driven tests](#table)
    20  * [Questions?](#questions)
    21  
    22  <a name="existing"></a>
    23  ## Running tests for Sia
    24  Go's comprehensive [test package][pkg/testing] makes testing straightforward,
    25  particularly when you use the bundled tools included in the
    26  [Sia makefile][makefile], including `make test`, `make cover`, `make bench`,
    27  and their variants.
    28  
    29  <a name="update"></a>
    30  ### Updating code before testing
    31  If you just want to run existing tests on the codebase as is, you just need to
    32  pull the latest version of the original repo to your master branch.  (If that 
    33  sentence didn't make sense, go read
    34  [doc/Guide to Contributing to Sia.md][guide].)
    35  
    36  ```bash
    37  # Make sure you are in the right directory.
    38  $ cd $GOPATH/src/github.com/<your Github username>/Sia
    39  # Also make sure you're working with the right branch.
    40  $ git checkout master
    41  # Pull latest changes from origin, the original Sia repo. 
    42  $ git pull origin master
    43  # Update your fork of the repo, which should be set up as a remote.
    44  $ git push <remote>  master
    45  ```
    46  
    47  If you want to run tests on the new code you've added, first make sure the rest
    48  of the code is up to date. New code should be on its own branch (again, see
    49  [doc/Guide to Contributing to Sia.md][guide]).
    50  
    51  ```bash
    52  # Make sure you are in the right directory.
    53  $ cd $GOPATH/src/github.com/<your Github username>/Sia
    54  # Checkout the branch you made the changes on.
    55  $ git checkout <branch name>
    56  # Stash any tracked but uncommitted changes.
    57  $ git stash
    58  # Then switch back to `master` and update it to match the original repo.
    59  $ git checkout master
    60  $ git pull origin master
    61  # Update your fork of the repo, which you should have set up as a remote.
    62  $ git push <remote>  master
    63  # Make the updated `master` the new base of the branch you made the changes on,
    64  # which involves reapplying all the commits made to that branch.  Without the
    65  # `--ignore-date` flag, git rebase changes the date on all the commits to the
    66  # current date.
    67  $ git checkout <branch name>
    68  $ git rebase master --ignore-date
    69  # Restore the changes you stashed earlier.
    70  $ git stash pop
    71  ```
    72  When you call `rebase`, you may run into some merge conflicts.  Luke Champine's
    73  ['How to into git and GitHub'][luke] has more details (and many useful tricks).
    74  
    75  Once the branch you want to test is up to date, you're ready to run some tests.
    76  
    77  <a name="entire"></a>
    78  ### Testing the entire build
    79  The `make test` command runs all tests (functions starting with `Test` in
    80  `_test.go` files) for each package, setting off a panic for any test that runs
    81  longer than 5s.  For verbose output, run `make test-v` (which panics after 15s
    82  instead of 5s).  Finally, `make test-long` has verbose output, only panics when
    83  a test takes 5 minutes, and also cleans up your code using `gofmt` and `golint`. 
    84  **You should run** `make test-long` **before each pull request.**
    85  
    86  Run `make cover` to run all tests for each package and generate color-coded
    87  .html visualizations of test coverage by function for each source file.  Open
    88  `cover/<module>.html` in a browser to inspect a module's test coverage. For 
    89  example, here's part of the html file generated for the persist package: 
    90  
    91  ![Screenshot](assets/covertool.png)
    92  
    93  Meanwhile, `make bench` will call `gofmt` on all packages, then run all
    94  benchmarks (functions starting with `Benchmark` in `_test.go` files).
    95  
    96  <a name="particular"></a>
    97  ### Testing a particular package or function
    98  To run tests for just a certain package, run `make test pkgs=./<package>`. To run 
    99  a certain test function, run `make test pkgs=./<package> run=<function>`. The same
   100  goes for `make test-long`, `make cover` and `make bench`.
   101  
   102  For example, running `test-long` on the package persist produces this output:
   103  
   104  ```bash
   105  $ make test-long pkgs=./persist
   106  rm -rf release doc/whitepaper.aux doc/whitepaper.log doc/whitepaper.pdf
   107  gofmt -s -l -w ./persist
   108  go install ./persist
   109  go vet ./persist
   110  go test -v -race -tags='testing debug' -timeout=300s ./persist -run=Test
   111  === RUN   TestOpenDatabase
   112  --- PASS: TestOpenDatabase (0.42s)
   113  === RUN   TestSaveLoad
   114  --- PASS: TestSaveLoad (0.00s)
   115  === RUN   TestSaveLoadFile
   116  --- PASS: TestSaveLoadFile (0.01s)
   117  === RUN   TestSaveLoadFileSync
   118  --- PASS: TestSaveLoadFileSync (0.00s)
   119  === RUN   TestLogger
   120  --- PASS: TestLogger (0.00s)
   121  === RUN   TestLoggerCritical
   122  --- PASS: TestLoggerCritical (0.00s)
   123  === RUN   TestIntegrationRandomSuffix
   124  --- PASS: TestIntegrationRandomSuffix (0.01s)
   125  === RUN   TestAbsolutePathSafeFile
   126  --- PASS: TestAbsolutePathSafeFile (0.00s)
   127  === RUN   TestRelativePathSafeFile
   128  --- PASS: TestRelativePathSafeFile (0.00s)
   129  PASS
   130  ok  	github.com/NebulousLabs/Sia/persist	1.485s
   131  $
   132  ``` 
   133  
   134  <a name="write"></a>
   135  ## Writing new tests for Sia
   136  When you run `make cover`, you'll notice that many files have pretty low
   137  coverage.  We're working on fixing that, but we could use your help.
   138  
   139  <a name="naming"></a>
   140  ### A few guidelines
   141  * The test functions for `filename.go` should go in `filename_test.go` in the
   142      same directory and package.
   143  * A test function name should start with `Test` and clearly convey what is
   144      being tested.
   145  * You should declare function-specific variables and constants locally (inside
   146      the test function) instead of globally (outside the test function).  [That 
   147  	holds in general][global], not just for tests.
   148  * As always, code should adhere to the standards and conventions laid out in
   149      [doc/Developers.md][developers].
   150  
   151  <a name="basic"></a>
   152  ### Basic test format
   153  Suppose we'd like to test the Bar method belonging to type Foo.  
   154  
   155  ```go
   156  // TestFoo checks that the Bar method on type Foo responds correctly to a normal
   157  // input and returns the expected error when given a bad input.
   158  func TestFoo(t *testing.T) {
   159  	foo, err := NewFoo()
   160  	if err != nil {
   161  	// If NewFoo failed, we can't continue testing.
   162  	t.Fatal(err)
   163  	}
   164  
   165  	// Try a normal input; should succeed.
   166  	err := foo.Bar(3)
   167  	if err != nil {
   168  		// Report the error, but don't abort the test.
   169  		t.Error(err)
   170  	}
   171  
   172  	// Try a bad input; should return an error.
   173  	// NOTE: Always prefer to compare to a specific error, rather than 
   174  	// err == nil
   175  	err = Foo.Bar(0)
   176  	if err != errDivideByZero {
   177  		t.Errorf("expected errDivideByZero, got %v", err)
   178  	}
   179  }
   180  
   181  ```
   182  
   183  <a name="table"></a>
   184  ### Table-driven tests in Go
   185  If you're looking to test a bunch of inputs, write a [table-driven test][table]
   186  with a slice of anonymous structs. For example, see `TestParseFileSize` in 
   187  [siac/parse_test.go][parse_test]:
   188  
   189  ```go
   190  func TestParseFilesize(t *testing.T) {
   191  	// Define a table of test cases in the form of a slice of anonymous structs.
   192  	tests := []struct {
   193  		in, out string
   194  		err     error
   195  	}{
   196  		{"1b", "1", nil},
   197  		{"1KB", "1000", nil},
   198  		{"1MB", "1000000", nil},
   199  		{"1GB", "1000000000", nil},
   200  		{"1TB", "1000000000000", nil},
   201  		{"1KiB", "1024", nil},
   202  		{"1MiB", "1048576", nil},
   203  		{"1GiB", "1073741824", nil},
   204  		{"1TiB", "1099511627776", nil},
   205  		{"", "", errUnableToParseSize},
   206  		{"123", "123", nil},
   207  		{"123TB", "123000000000000", nil},
   208  		{"123GiB", "132070244352", nil},
   209  		{"123BiB", "", errUnableToParseSize},
   210  		{"GB", "", errUnableToParseSize},
   211  		{"123G", "", errUnableToParseSize},
   212  		{"123B99", "", errUnableToParseSize},
   213  		{"12A3456", "", errUnableToParseSize},
   214  		{"1.23KB", "1230", nil},
   215  		{"1.234KB", "1234", nil},
   216  		{"1.2345KB", "1234", nil},
   217  	}
   218  	// Loop through the table of test cases to make sure ParseFileSize returns 
   219  	// the expected output and error for each.
   220  	for _, test := range tests {
   221  		res, err := parseFilesize(test.in)
   222  		if res != test.out || err != test.err {
   223  			t.Errorf("parseFilesize(%v): expected %v %v, got %v %v", test.in, test.out, test.err, res, err)
   224  		}
   225  	}
   226  }
   227  ```
   228  <a name="questions"></a>
   229  ## Questions?
   230  Read these if you haven't already:
   231  * [doc/Guide to Contributing to Sia.md][guide]: getting started with Go, Sia,
   232      and git
   233  * [doc/Developers.md][developers]: conventions and quality standards for Sia
   234      code
   235  
   236  Some other useful resources, some of which have been linked to already:
   237  * [Golang.org page on the go testing package][pkg/testing]
   238  * [Writing Table-Driven Tests in Go][table]
   239  * [How to Write Benchmarks in Go][cheney-benchmarks]
   240  * [How to into git and GitHub][luke]: an essential introduction to git
   241  
   242  And feel free to ask questions on the [#core-dev channel][discord] on the Sia Discord. 
   243  Odds are, someone else is wondering the same thing.
   244  
   245  [pkg/testing]: https://golang.org/pkg/testing/
   246  [makefile]: https://github.com/NebulousLabs/Sia/blob/master/Makefile
   247  [luke]: https://gist.github.com/lukechampine/6418449
   248  [guide]: https://github.com/NebulousLabs/Sia/blob/master/doc/Guide%20to%20Contributing%20to%20Sia.md
   249  [developers]: https://github.com/NebulousLabs/Sia/blob/master/doc/Developers.md
   250  [table]: http://dave.cheney.net/2013/06/09/writing-table-driven-tests-in-go
   251  [boltdb_test.go]: https://github.com/NebulousLabs/Sia/blob/master/persist/boltdb_test.go
   252  [cheney-benchmarks]: http://dave.cheney.net/2013/06/30/how-to-write-benchmarks-in-go
   253  [pkg/testing]: https://golang.org/pkg/testing/
   254  [discord]: https://discord.gg/sia
   255  [parse_test]: https://github.com/NebulousLabs/Sia/blob/master/siac/parse_test.go
   256  [global]: http://c2.com/cgi/wiki?GlobalVariablesAreBad